package edu.univercidade.tcc.sap.client.widget;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.gwt.cell.client.ActionCell;
import com.google.gwt.cell.client.DatePickerCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextInputCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;
import com.google.gwt.view.client.SingleSelectionModel;

import edu.univercidade.tcc.sap.client.Messages;
import edu.univercidade.tcc.sap.client.UserService;
import edu.univercidade.tcc.sap.client.UserServiceAsync;
import edu.univercidade.tcc.sap.model.EmailNotification;
import edu.univercidade.tcc.sap.model.User;

public class UserTable extends CellTable<User> implements MenuTable {

	private final class DeleteDelegateCommand implements
			ActionCell.Delegate<User> {
		@Override
		public void execute(final User arg0) {
			userService.deleteUser(arg0, new AsyncCallback<Void>() {

				@Override
				public void onFailure(Throwable arg0) {
					GWT.log("Erro na exclusão de usuários", arg0);
				}

				@Override
				public void onSuccess(Void v) {
					users.remove(arg0);
					UserTable.this.setRowCount(users.size());
					UserTable.this.setRowData(users);
					UserTable.this.redraw();
				}
			});

		}
	}

	private final class ActiveUsersCallback implements
			AsyncCallback<User[]> {
		@Override
		public void onFailure(Throwable arg0) {
			GWT.log("Erro na recuperação de usuários", arg0);
			UserTable.this.setRowCount(users.size(), true);
			UserTable.this.setRowData(0, users);
			UserTable.this.redraw();
			arg0.printStackTrace();
		}

		@SuppressWarnings("unchecked")
		@Override
		public void onSuccess(User[] arg0) {
			users.addAll(Arrays.asList(arg0));
			UserTable.this.setRowCount(users.size(), true);
			UserTable.this.setRowData(0, users);
			UserTable.this.redraw();
		}
	}

	private final Messages messages = GWT.create(Messages.class);
	private final UserServiceAsync userService = GWT.create(UserService.class);
	private final Set<User> updateList = new HashSet<User>();
	private final List<User> newList = new ArrayList<User>();
	private final List<User> users = new ArrayList<User>();

	public UserTable() {
		super(new ProvidesKey<User>() {
			public Object getKey(User item) {
				return (item == null) ? null : item.getId();
			}
		});

		TextColumn<User> loginColumn = new TextColumn<User>() {
			@Override
			public String getValue(User user) {
				return user.getLogin();
			}
		};
		addColumn(loginColumn, messages.login());
		loginColumn.setFieldUpdater(new FieldUpdater<User, String>() {
			public void update(int index, User object, String value) {
				object.setLogin(value);
				updateList.add(object);
			}
		});

		final TextInputCell nameCell = new TextInputCell();
		Column<User, String> nameColumn = new Column<User, String>(nameCell) {
			@Override
			public String getValue(User user) {
				return user.getFirstname();
			}
		};
		addColumn(nameColumn, messages.firstName());
		nameColumn.setFieldUpdater(new FieldUpdater<User, String>() {
			public void update(int index, User object, String value) {
				object.setFirstname(value);
				updateList.add(object);
			}
		});

		final TextInputCell surnameCell = new TextInputCell();
		Column<User, String> surnameColumn = new Column<User, String>(
				surnameCell) {

			@Override
			public String getValue(User user) {
				return user.getLastname();
			}
		};
		addColumn(surnameColumn, messages.lastName());
		surnameColumn.setFieldUpdater(new FieldUpdater<User, String>() {
			public void update(int index, User object, String value) {
				object.setLastname(value);
				updateList.add(object);
			}
		});

		final TextInputCell emailCell = new TextInputCell();
		Column<User, String> emailColumn = new Column<User, String>(emailCell) {

			@Override
			public String getValue(User user) {
				return user.getMail();
			}
		};
		addColumn(emailColumn, messages.email());
		emailColumn.setFieldUpdater(new FieldUpdater<User, String>() {
			public void update(int index, User object, String value) {
				object.setMail(value);
				updateList.add(object);
			}
		});

		List<String> emailNotificationValues = new ArrayList<String>();
		for (EmailNotification en : EmailNotification.values()) {
			emailNotificationValues.add(en.toString());
		}
		final SelectionCell emailNotificationCell = new SelectionCell(
				emailNotificationValues);
		Column<User, String> emailNotificationColumn = new Column<User, String>(
				emailNotificationCell) {

			@Override
			public String getValue(User user) {
				return user.getMailNotification().toString();
			}
		};
		addColumn(emailNotificationColumn, messages.mailNotification());
		emailNotificationColumn
				.setFieldUpdater(new FieldUpdater<User, String>() {
					public void update(int index, User object, String value) {
						object.setMailNotification(EmailNotification.valueOf(
								EmailNotification.class, value.toUpperCase()));
						updateList.add(object);
					}
				});

		Column<User, Date> dateColumn = new Column<User, Date>(
				new DatePickerCell(DateTimeFormat.getShortDateTimeFormat())) {
			@Override
			public Date getValue(User user) {
				return user.getLastLoginOn();
			}
		};
		addColumn(dateColumn, messages.lastLogin());

		final ActionCell<User> deleteCell = new ActionCell<User>(
				messages.deleteButton(), new DeleteDelegateCommand());
		Column<User, User> deleteColumn = new Column<User, User>(deleteCell) {

			@Override
			public User getValue(User arg0) {
				return arg0;
			}
		};
		addColumn(deleteColumn, "");

		// Push data into the CellList.
		userService.activeUsers(new ActiveUsersCallback());

		// Add a selection model using the same keyProvider.
		SelectionModel<User> selectionModel = new SingleSelectionModel<User>(
				getKeyProvider());
		setSelectionModel(selectionModel);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.univercidade.tcc.sap.client.widget.TableMenuCommand#updateHandler()
	 */
	@Override
	public ClickHandler updateHandler() {
		return new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				if (newList.size() == 1)
					userService.createUser(newList.get(0),
							new AsyncCallback<User>() {

								@Override
								public void onFailure(Throwable arg0) {
									// TODO tratar erro e criar mensagem
									GWT.log("Erro na criação de usuário", arg0);
									newList.clear();
								}

								@Override
								public void onSuccess(User arg0) {
									newList.clear();
									users.remove(users.size() - 1);
									users.add(arg0);
									UserTable.this.setRowCount(users.size());
									UserTable.this.setRowData(users);
									UserTable.this.redraw();
								}
							});
				for (User user : updateList) {
					userService.updateUser(user, new AsyncCallback<Void>() {

						@Override
						public void onFailure(Throwable arg0) {
							// TODO Auto-generated method stub
							GWT.log("Erro na atualização de usuários", arg0);
							updateList.clear();
						}

						@Override
						public void onSuccess(Void arg0) {
							UserTable.this.redraw();
							updateList.clear();
						}
					});
				}
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.univercidade.tcc.sap.client.widget.TableMenuCommand#newHandler()
	 */
	@Override
	public ClickHandler newHandler() {
		return new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				if (newList.size() == 0) {
					User user = new User();
					newList.add(user);
					users.add(user);
					UserTable.this.setRowCount(users.size());
					UserTable.this.setRowData(users);
					UserTable.this.redraw();
				}
			}
		};
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.univercidade.tcc.sap.client.widget.TableMenuCommand#resetHandler()
	 */
	@Override
	public ClickHandler resetHandler() {
		return new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				newList.clear();
				updateList.clear();
				users.remove(users.size() - 1);
				UserTable.this.setRowCount(users.size());
				UserTable.this.setRowData(users);
				UserTable.this.redraw();
			}
		};
	}
}
